package org.totoro.api;

import lombok.extern.slf4j.Slf4j;
import org.objectweb.asm.*;
import org.totoro.AnalysisService;

import java.io.IOException;

/**
 * ClassReader.SKIP_CODE：
 * <p>
 * 跳过代码属性的标志（个人感觉就是没有方法会被特地跳过）
 * <p>
 * ClassReader.SKIP_FRAMES：
 * <p>
 * 跳过StackMap和StackMapTable属性的标志。跳过MethodVisitor.visitFrame方法。
 * <p>
 * ClassReader.SKIP_DEBUG：
 * <p>
 * 跳过SourceFile，SourceDebugExtension，LocalVariableTable，LocalVariableTypeTable和LineNumberTable属性的标志。跳过ClassVisitor.visitSource, MethodVisitor.visitLocalVariable, MethodVisitor.visitLineNumber方法。
 * <p>
 * ClassReader.EXPAND_FRAMES：
 * <p>
 * 用于展开堆栈映射帧的标志。这会大大降低性能。（文档上写的，感觉上用不到）
 *
 * @author daocr
 * @date 2020/9/23
 */
@Slf4j
public class ClassVisitorTest extends ClassVisitor {
    private int code;


    public static void main(String[] args) throws IOException {

        String n = AnalysisService.class.getName();
        ClassReader cr = new ClassReader(n);

//        ClassNode cn = new ClassNode();
        ClassVisitorTest cn = new ClassVisitorTest();
        cr.accept(cn, Opcodes.ASM8);
//        List<MethodNode> methods = cn.methods;
//        for (MethodNode method : methods) {
//
//            InsnList instructions = method.instructions;
//            for (AbstractInsnNode instruction : instructions) {
//                System.out.println(instruction);
//            }
//        }


    }

    public ClassVisitorTest() {
        super(Opcodes.ASM8);
    }

    /**
     * 访问类头部信息
     *
     * @param version    类版本
     * @param access     类访问标识符public等
     * @param name       类名称
     * @param signature  类签名（非泛型为NUll）
     * @param superName  类的父类
     * @param interfaces 类实现的接口
     */

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        log.info("文件头信息： version :{}\t access: {}\tname: {}\t signature: {}\tsuperName:{}\t interfaces:{}", version, access, name, signature, superName, interfaces);
        super.visit(version, access, name, signature, superName, interfaces);
    }

    /**
     * 访问类的源文件.
     *
     * @param source 源文件名称
     * @param debug  附加的验证信息，可以为空
     */
    @Override
    public void visitSource(String source, String debug) {
        log.info("源文件： source :{}\t debug: {}", source, debug);
        super.visitSource(source, debug);
    }

    @Override
    public ModuleVisitor visitModule(String name, int access, String version) {
        log.info("模型： name :{}\t access: {}\tversion: {}", name, access, version);
        return super.visitModule(name, access, version);
    }

    @Override
    public void visitNestHost(String nestHost) {
        log.info("模型： nestHost ：{} ", nestHost);
        super.visitNestHost(nestHost);
    }

    @Override
    public void visitOuterClass(String owner, String name, String descriptor) {
        log.info(" owner ：{}\towner ：{}\towner ：{} ", owner, name, descriptor);
        super.visitOuterClass(owner, name, descriptor);
    }

    /**
     * 访问类的注解
     *
     * @param descriptor 注解类的类描述
     * @param visible    runtime时期注解是否可以被访问
     * @return 返回一个注解值访问器
     */
    @Override
    public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
        log.info(" descriptor ：{}\tvisible ：{}", descriptor, visible);
        return super.visitAnnotation(descriptor, visible);
    }

    /**
     * 访问标注在类型上的注解
     *
     * @param typeRef
     * @param typePath
     * @param descriptor
     * @param visible
     * @return
     */
    @Override
    public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
        log.info(" typeRef ：{}\ttypePath ：{}\ttypePath ：{}\tdescriptor ：{}\tvisible ：{}", typeRef, typePath, descriptor, visible);
        return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
    }

    /**
     * 访问一个类的属性
     *
     * @param attribute 类的属性
     */
    @Override
    public void visitAttribute(Attribute attribute) {
        log.info("attribute: {}", attribute);
        super.visitAttribute(attribute);
    }

    @Override
    public void visitNestMember(String nestMember) {
        log.info("nestMember: {}", nestMember);
        super.visitNestMember(nestMember);
    }

    /**
     * 访问内部类信息
     *
     * @param name
     * @param outerName
     * @param innerName
     * @param access
     */
    @Override
    public void visitInnerClass(String name, String outerName, String innerName, int access) {
        log.info("name: {}\touterName: {}\tinnerName: {}\taccess: {}", name, outerName, innerName, access);
        super.visitInnerClass(name, outerName, innerName, access);
    }


    /**
     * 访问类的字段
     *
     * @param access
     * @param name
     * @param descriptor
     * @param signature
     * @param value
     * @return
     */
    @Override
    public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
        log.info("access: {}\tname: {}\tdescriptor: {}\tsignature: {} \tvalue: {} ", access, name, descriptor, signature, value);
        return super.visitField(access, name, descriptor, signature, value);
    }

    /**
     * 访问类的方法
     *
     * @param access
     * @param name
     * @param descriptor
     * @param signature
     * @param exceptions
     * @return
     */
    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        log.info("access: {}\tname: {}\tdescriptor: {}\tsignature: {} \texceptions: {} ", access, name, descriptor, signature, exceptions);


        MethodVisitorTest methodVisitorTest = new MethodVisitorTest(Opcodes.ASM8);

        return methodVisitorTest;
    }

    @Override
    public void visitEnd() {
        super.visitEnd();
    }
}
